
/** INCLUDES *******************************************************/
#include "USB/usb.h"
#include "USB/usb_function_generic.h"

#include "HardwareProfile.h"
#include "user.h"

#include "DAC.h"
#include "Fpga.h"
#include <timers.h>
#include <math.h>

/** V A R I A B L E S ********************************************************/

#if defined(__18F2455) || defined(__18F2550) || defined(__18F4455) || defined(__18F4550)\
    || defined(__18F2458) || defined(__18F2453) || defined(__18F4558) || defined(__18F4553)
    #pragma udata USB_VARIABLES=0x500
#elif defined(__18F4450) || defined(__18F2450)
    #pragma udata USB_VARIABLES=0x480
#else
    #pragma udata
#endif

DATA_PACKET INPacket;
DATA_PACKET OUTPacket;
#pragma udata

USB_HANDLE USBGenericOutHandle = 0;
USB_HANDLE USBGenericInHandle = 0;

BOOL blinkStatusValid = TRUE;
BYTE counter;

BYTE sweepstate;
BOOL sweeprunning;

DWORD_VAL sweepstart;
DWORD_VAL sweepend;
DWORD_VAL sweepcursor;

BYTE  currsweepstate;
DWORD currsweepstart;
DWORD currsweepend;
DWORD currsweepcursor;

WORD sweepcounter;
BYTE cursorcounter;

signed long sweepstep;
signed long sweepstepremain;

DWORD sweepfreq;
DWORD sweepfreqhi;
signed long sweepfreqlo;

WORD_VAL dacval;

BYTE blinkspeed;

/** P R I V A T E  P R O T O T Y P E S ***************************************/

void BlinkUSBStatus(void);
void ServiceRequests(void);

/** D E C L A R A T I O N S **************************************************/
#pragma code
void UserInit(void)
{
    blinkspeed = 2;

    INTCONbits.GIE = 0;
    RCONbits.IPEN = 0;			// No int priority
    INTCONbits.PEIE = 1;		// Peripheral INT enable

    mInitAllLEDs();
    InitDAC();
    InitFpga();
    
    T0CON = 0b10001000;//0b11000111;
    TMR0H = 0xFC;
    TMR0L = 0x00;
    INTCONbits.TMR0IF = 0;
    INTCONbits.TMR0IE = 1;
      
    INTCONbits.GIE = 1;			// enable global

    blinkStatusValid = TRUE;
    sweepstate = 0;
    sweeprunning = FALSE;
}//end UserInit


// * Overview:        This function is a place holder for other user routines.
// *                  It is a mixture of both USB and non-USB tasks.
void ProcessIO(void)
{   
    //Blink the LEDs according to the USB device status
    if(blinkStatusValid)
    {
        BlinkUSBStatus();
    }

    // User Application USB tasks
    if((USBDeviceState < CONFIGURED_STATE)||(USBSuspendControl==1)) return;

    //respond to any USB commands that might have come over the bus
    ServiceRequests();

}//end ProcessIO


// * Overview:        This function takes in the commands from the PC from the
// *                  application and executes the commands requested
void ServiceRequests(void)
{
	DWORD_VAL freq;
	WORD_VAL phase;
	WORD_VAL daval;
    
    //Check to see if data has arrived
    if(!USBHandleBusy(USBGenericOutHandle))
    {        
        //if the handle is no longer busy then the last
        //transmission is complete
       
        counter = 0;

        INPacket.DP.CMD=OUTPacket.DP.CMD;
        INPacket.DP.Len=OUTPacket.DP.Len;		

        //process the command
        switch(OUTPacket.DP.CMD)
        {
            case READ_VERSION:
		INPacket.DP.Len = 2;
                INPacket.DP.Data[0] = MINOR_VERSION;
                INPacket.DP.Data[1] = MAJOR_VERSION;
                counter=0x04;
                break;

            case READ_PROPS:
		INPacket.DP.Len = 12;

                INPacket.DP.Data[0] = FPGA_SAMPLE_NUM >> 24;
                INPacket.DP.Data[1] = (FPGA_SAMPLE_NUM & 0x00ffffff) >> 16;
		INPacket.DP.Data[2] = (FPGA_SAMPLE_NUM & 0x00ffff) >> 8;
		INPacket.DP.Data[3] = (FPGA_SAMPLE_NUM & 0x00ff);

                INPacket.DP.Data[4] = FPGA_FREQ >> 24;
                INPacket.DP.Data[5] = (FPGA_FREQ & 0x00ffffff) >> 16;
		INPacket.DP.Data[6] = (FPGA_FREQ & 0x00ffff) >> 8;
		INPacket.DP.Data[7] = (FPGA_FREQ & 0x00ff);

                INPacket.DP.Data[8] = FPGA_SAMPLE_RESOLUTION;
                INPacket.DP.Data[9] = FPGA_PHASE_RESOLUTION;
                INPacket.DP.Data[10] = FPGA_ACC_RESOLUTION;
                INPacket.DP.Data[11] = FPGA_FREQ_RESOLUTION;
                counter=14;
                break;

            case INITWRITE:
                FpgaInitWrite();
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case WRITERAM:
                FpgaWrite(OUTPacket.DP.Data, OUTPacket.DP.Len);	// write data to ram
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case STARTGEN:
                freq.byte.LB = OUTPacket.DP.Data[0];
                freq.byte.HB = OUTPacket.DP.Data[1];
                freq.byte.UB = OUTPacket.DP.Data[2];
                freq.byte.MB = OUTPacket.DP.Data[3];
                phase.byte.LB = OUTPacket.DP.Data[4];
                phase.byte.HB = OUTPacket.DP.Data[5];
                FpgaInitGenerate(freq.Val, phase.Val, OUTPacket.DP.Data[6]);
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case MANCLK:									// manual clock. data not interpreted.
                ManualClk();
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case FPGAHARDRESET:
                FpgaResetStop();
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case SETDAC:
                daval.byte.HB = OUTPacket.DP.Data[1];
                daval.byte.LB = OUTPacket.DP.Data[2];
                SetDAC(OUTPacket.DP.Data[0], daval);
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case SETFREQ:
                freq.byte.LB = OUTPacket.DP.Data[0];
                freq.byte.HB = OUTPacket.DP.Data[1];
                freq.byte.UB = OUTPacket.DP.Data[2];
                freq.byte.MB = OUTPacket.DP.Data[3];
                phase.byte.LB = OUTPacket.DP.Data[4];
                phase.byte.HB = OUTPacket.DP.Data[5];
                FpgaSetFreq(freq.Val);
                FpgaSetPhase(phase.Val);
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case SETSWEEP:
                sweepstart.byte.LB = OUTPacket.DP.Data[0];
                sweepstart.byte.HB = OUTPacket.DP.Data[1];
                sweepstart.byte.UB = OUTPacket.DP.Data[2];
                sweepstart.byte.MB = OUTPacket.DP.Data[3];
                sweepend.byte.LB = OUTPacket.DP.Data[4];
                sweepend.byte.HB = OUTPacket.DP.Data[5];
                sweepend.byte.UB = OUTPacket.DP.Data[6];
                sweepend.byte.MB = OUTPacket.DP.Data[7];
                sweepcursor.byte.LB = OUTPacket.DP.Data[8];
                sweepcursor.byte.HB = OUTPacket.DP.Data[9];
                sweepcursor.byte.UB = OUTPacket.DP.Data[10];
                sweepcursor.byte.MB = OUTPacket.DP.Data[11];
                sweepstate = OUTPacket.DP.Data[12];
                INPacket.DP.Len = 1;
                INPacket.DP.Data[0] = 0x00;
                counter = 3;
                break;

            case RESET:
#ifdef __18CXX
                Reset();
#endif
                break;
                
            default:
#ifdef __18CXX
                Nop();
#endif
                break;
        }//end switch()
        if(counter != 0)
        {
            if(!USBHandleBusy(USBGenericInHandle))
            {
                USBGenericInHandle = USBGenWrite(USBGEN_EP_NUM,(BYTE*)&INPacket,counter);
            }
        }//end if
        
        //Re-arm the OUT endpoint for the next packet
        USBGenericOutHandle = USBGenRead(USBGEN_EP_NUM,(BYTE*)&OUTPacket,USBGEN_EP_SIZE);
    }//end if

}//end ServiceRequests


// * Overview:        BlinkUSBStatus turns on and off LEDs 
// *                  corresponding to the USB device state.
void BlinkUSBStatus(void)
{
    static WORD led_count=0;
    static BYTE direction;
    static WORD pw = 20;
    
    //if(led_count == 0)led_count = 10000U;

    if(led_count == 0)
    {
        led_count = 500U;

        if(direction == 0)
        {
	    pw += blinkspeed;
	    if (pw > 480) direction = 1;
	}
	else
	{
            pw -= blinkspeed;
            if (pw < 20) direction = 0;
	}
    }

    led_count--;

    #define mLED_Both_Off()         {mLED_1_Off();mLED_2_Off();}
    #define mLED_Both_On()          {mLED_1_On();mLED_2_On();}
    #define mLED_Only_1_On()        {mLED_1_On();mLED_2_Off();}
    #define mLED_Only_2_On()        {mLED_1_Off();mLED_2_On();}

    if(USBSuspendControl == 1)
    {
        /*if(led_count==0)
        {
            mLED_1_Toggle();
            if(mGetLED_1())
            {
                mLED_2_On();
            }
            else
            {
                mLED_2_Off();
            }
        }*///end if
        if(led_count==pw)
        {
            mLED_Only_1_On();
        }
        if(led_count==0)
        {
            mLED_Both_Off();        // LED1 pulse
        }//end if

    }
    else
    {
        if(USBDeviceState == DETACHED_STATE)
        {
            //mLED_Both_Off();
            /*if(led_count == 0)
            {
                mLED_1_Toggle();
                mLED_2_Off();
            }*///end if
            if(led_count==pw)
            {
                mLED_Only_1_On();
            }
            if(led_count==0)
            {
                mLED_Both_Off();        // LED1 pulse
            }//end if
        }
        else if(USBDeviceState == ATTACHED_STATE)
        {
            mLED_Both_On();
        }
        else if(USBDeviceState == POWERED_STATE)
        {
            mLED_Only_1_On();
        }
        else if(USBDeviceState == DEFAULT_STATE)
        {
            mLED_Only_2_On();
        }
        else if(USBDeviceState == ADDRESS_STATE)
        {
            if(led_count == 0)
            {
                mLED_2_Toggle();
                mLED_1_Off();
            }//end if
        }
        else if(USBDeviceState == CONFIGURED_STATE)
        {
            /*if(led_count==0)
            {      
                mLED_1_Toggle();
                if(mGetLED_1())
                {
                    mLED_2_Off();
                }
                else
                {
                    mLED_2_On();
                }
            }*///end if
            	if(led_count==pw)
		{
                    mLED_Only_2_On();
		}
	        if(led_count==0)
	        {
	            mLED_Both_Off();        // LED2 pulse
	        }//end if
        }//end if(...)
    }//end if(UCONbits.SUSPND...)

}//end BlinkUSBStatus

void ProcessSweep()
{
    if (sweeprunning == TRUE)   //process sweep
    {
        if (sweepcounter < 256) // check current counter
        {
            if (cursorcounter != 0)
            {
                if (sweepstep > 0) // sweeping up
                {
                    if ((sweepfreq > currsweepcursor) == TRUE) // when cursor reached, count to ten
                    {
                        cursorcounter--;
                        return;
                    }
                }
                else // sweeping down
                {
                    if ((sweepfreq < currsweepcursor) == TRUE)
                    {
                        cursorcounter--;
                        return;
                    }
                }
            }

            sweepcounter++;
            dacval.Val = 4096 - (sweepcounter * 16);
            SetDAC(1, dacval);
            if (currsweepstate == 1)    // linear sweep
            {
                sweepfreqhi += sweepstep;
                sweepfreqlo += sweepstepremain;
                sweepfreq = sweepfreqhi + (sweepfreqlo / 256);

                FpgaSetFreq(sweepfreq);
            }
            /*else    // logarithmic sweep
            {
                float logval = log10(((float)sweepcounter / (float)512) * 9 + 1);
                sweepfreq = (DWORD)(currsweepstart + (sweepstep * logval));
                FpgaSetFreq(sweepfreq);
            }*/ // TODO: Logarithmic sweep is not implemented due to performance and memory limitations
        }
        else                    // stop sweep after 512 steps
        {
            sweeprunning = FALSE;
        }
    }
    else    // handle changes
    {
        if (sweepstate != 0)    // sweep is set to run
        {
            sweepcounter = 0;
            currsweepstart = sweepstart.Val;    // copy parameters for run
            currsweepend = sweepend.Val;
            currsweepcursor = sweepcursor.Val;
            currsweepstate = sweepstate;

            cursorcounter = 10;                 // cursor will be thicker
            sweepfreq = currsweepstart;
            sweepfreqhi = sweepfreq;
            sweepfreqlo = 0;

            if (sweepstate == 1)
            {
                sweepstep = (signed long)(currsweepend - currsweepstart) / 256;
                sweepstepremain = (signed long)(currsweepend - currsweepstart) % 256;
            }
            /*else
            {
                sweepstep = (float)(currsweepend - currsweepstart);
            }*/ // TODO: Logarithmic sweep is not implemented due to performance and memory limitations

            sweeprunning = TRUE;                // start sweep
        }
    }
}

/** EOF user.c ***************************************************************/
